package com.smedi.ismedi.authoritymanagement.core.application.service.impl;

import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import cn.hutool.crypto.SecureUtil;
import com.smedi.ismedi.authority.starter.response.AuthorityAccessResponse;
import com.smedi.ismedi.authority.starter.util.AuthorityUtil;
import com.smedi.ismedi.authority.starter.util.JsonHelper;
import com.smedi.ismedi.authoritymanagement.core.application.query.vo.FrameStructureVo;
import com.smedi.ismedi.authoritymanagement.core.application.service.ClientLoginApplicationService;
import com.smedi.ismedi.authoritymanagement.core.domain.aggregatemodel.*;
import com.smedi.ismedi.authoritymanagement.core.domain.repository.AccountBasicRepository;
import com.smedi.ismedi.authoritymanagement.core.domain.repository.RoleBasicRepository;
import com.smedi.ismedi.authoritymanagement.core.domain.repository.RoleMemberRepository;
import com.smedi.ismedi.authoritymanagement.core.domain.repository.UserTokenRepository;
import com.smedi.ismedi.authoritymanagement.core.domain.service.AccountBasicDomainService;
import com.smedi.ismedi.authoritymanagement.core.domain.service.FrameStructureDomainService;
import com.smedi.ismedi.authoritymanagement.core.domain.service.RolePermissionDetailDomainService;
import com.smedi.ismedi.authoritymanagement.core.domain.service.TermDomainService;
import com.smedi.ismedi.authoritymanagement.core.infrastructure.constant.ConstantField;
import com.smedi.ismedi.authoritymanagement.core.infrastructure.constant.CustomError;
import com.smedi.ismedi.authoritymanagement.core.port.adapter.service.ConstructionProjectRemoteApiService;
import com.smedi.ismedi.authoritymanagement.core.port.adapter.service.OrganizationRemoteApiService;
import com.smedi.ismedi.authoritymanagement.core.port.adapter.service.PersonnelRemoteApiService;
import com.smedi.ismedi.cache.starter.util.RedisUtil;
import com.smedi.ismedi.constructionproject.api.dto.response.ProjectAssignmentResponse;
import com.smedi.ismedi.personnel.api.dto.response.*;
import com.smedi.ismedi.personnel.api.feign.RemotePersonCoreFeignApi;
import com.smedi.ismedi.web.starter.exception.LogicException;
import com.smedi.ismedi.web.starter.util.DozerUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static com.smedi.ismedi.authority.starter.constant.AuthorityConstant.ISMEDI_ACCESS_TOKEN;
import static com.smedi.ismedi.authoritymanagement.core.infrastructure.constant.ConstantField.PersonLevelEnum.*;
import static com.smedi.ismedi.authoritymanagement.core.infrastructure.constant.ConstantField.TOKEN_TIME;

/**
 * TODO 写登录
 *
 * @Author: xulinjun
 * @Date: 2021-7-2 20:26
 */
@Slf4j
@Service
@AllArgsConstructor
public class ClientLoginApplicationServiceImpl implements ClientLoginApplicationService {
    private final PersonnelRemoteApiService personnelRemoteApiService;
    private final ConstructionProjectRemoteApiService constructionProjectRemoteApiService;
    private final OrganizationRemoteApiService organizationRemoteApiService;
    private final AccountBasicDomainService accountBasicDomainService;
    private final RolePermissionDetailDomainService rolePermissionDetailDomainService;
    private final FrameStructureDomainService frameStructureDomainService;
    private final TermDomainService termDomainService;
    private final AccountBasicRepository accountBasicRepository;
    private final UserTokenRepository userTokenRepository;
    private final RoleMemberRepository roleMemberRepository;
    private final RoleBasicRepository roleBasicRepository;
    private final DozerUtil dozerUtil;
    private final AuthorityUtil authorityUtil;
    private final RemotePersonCoreFeignApi remotePersonCoreFeignApi;
    private final RedisUtil redisUtil;
    private final JsonHelper jsonHelper;
    private static final String routerPath = "routerPath";
    private static final Random rand = new Random();

    /**
     * 获取登录信息
     *
     * @param account
     * @param password
     * @param path
     * @param express
     * @return
     */
    private AuthorityAccess clientLogin(String account, String password, String path, Long express, String clientId) {
        AuthorityAccess authorityAccess = accountBasicDomainService.login(account, password, clientId);
        boolean accessIsAdmin = false; // 是否是管理员

        // 如果当前用户是虚拟人员，则员工号默认为负数
        if (authorityAccess.getPersonId() < 0) {
            accessIsAdmin = true;
        } else {
            // 获取人员信息
            if (personnelRemoteApiService.checkPersonIsAvailable(authorityAccess.getPersonId())) {
                // 获取人员信息
                PersonResponse personResponse = personnelRemoteApiService.getQueryPersonDetailInfo(authorityAccess.getPersonId());

                authorityAccess.setEmployeeNum(personResponse.getEmployeeNum())
                        .setImageUUID(personResponse.getImageUUID())
                        .setLastName(personResponse.getLastName())
                        .setGenderMeaning(personResponse.getGenderMeaning())
                        .setInternal(personResponse.isInternal())
                        .setInternalAssignments(dozerUtil.convertor(personResponse.getInternalAssignments(), InternalAssignmentInfo.class))
                        .setProjectAssignments(dozerUtil.convertor(personResponse.getProjectAssignments(), ProjectAssignmentInfo.class));
            } else {
                accessIsAdmin = true;
            }
        }

        // 管理员赋值
        if (accessIsAdmin) {
            if (authorityAccess.isAdmin()) {
                authorityAccess.setLastName(authorityAccess.getUserName())
                        .setInternal(true)
                        .setVirtual(true); // 未找到人则说明是需求管理员
            } else {
                throw LogicException.raise(CustomError.PERSON_NOT_EXIST);
            }
        }

        // 判断服务器上是否已经有登陆信息
        userTokenRepository.saveTokenAccessAndExpress(path, authorityAccess, express);

        // 请求上绑定token
        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        request.getSession().setAttribute(ISMEDI_ACCESS_TOKEN, authorityAccess.getToken());

        return authorityAccess;
    }

    @Override
    public AuthorityAccess pcLogin(String account, String password, String clientId) {
        return clientLogin(account, password, ConstantField.accessSessionPcPath, ConstantField.clientPcLive, clientId);
    }

    @Override
    public AuthorityAccess mobileLogin(String account, String password, String clientId) {
        return clientLogin(account, password, ConstantField.accessSessionMobilePath, ConstantField.clientMobileLive, clientId);
    }

    @Override
    public void loginOut(String token) {
        userTokenRepository.deleteToken(token);
    }

    private void validateToken(String token) {
        if (token.length() != ConstantField.tokenLength) {
            throw LogicException.raise(CustomError.TOKEN_NOT_AVAILABLE);
        }
    }

    @Override
    public AuthorityAccess validateTokenAndGetAuthorityAccessAndRefreshExpress(String token) {
        validateToken(token);
        return userTokenRepository.getAuthorityAccessAndRefreshExpress(token, null);
    }

    @Override
    public void boundDataPermissionScope(String token, Map<String, List<Long>> maps) {
        validateToken(token);
        userTokenRepository.getAuthorityAccessAndRefreshExpress(token, maps);
    }

    /**
     * 根据角色权限生产菜单树结构
     *
     * @param frameStructure
     * @param scopes
     * @return
     */
    private FrameStructureVo generateFrameStructureTreeByScope(FrameStructure frameStructure, List<Long> scopes) {
        if (!frameStructure.isRoot()) {
            // 是否允许下坠
            boolean isAllow = authorityUtil.isAdmin() ? true : scopes.contains(frameStructure.getStructureId());
            if (isAllow) {
                frameStructure.setTerm(termDomainService.queryTermByTermIdAndType(frameStructure.getTermId(), frameStructure.getType()));
                // 只有父节点允许，才会去取子节点
                List<FrameStructure> children = frameStructureDomainService.queryChildren(frameStructure.getStructureId());
                for (FrameStructure child : children) {
                    FrameStructureVo childVo = generateFrameStructureTreeByScope(child, scopes);
                    if (childVo != null) {
                        frameStructure.getChildren().add(childVo);
                    }
                }
            } else {
                return null;
            }
        } else {
            // 根节点不需要判断
            List<FrameStructure> children = frameStructureDomainService.queryChildren(frameStructure.getStructureId());
            for (FrameStructure child : children) {
                FrameStructureVo childVo = generateFrameStructureTreeByScope(child, scopes);
                if (childVo != null) {
                    frameStructure.getChildren().add(childVo);
                }
            }
        }

        return dozerUtil.mapGeneric(frameStructure, FrameStructureVo.class);
    }

    private FrameStructureVo generateFrameStructureTreeByScopeNew(FrameStructure frameStructure, List<Long> scopes, List<FrameStructure> children) {
        Map<Long, List<FrameStructure>> map = children.stream().filter(x -> x.getParentId() != null).collect(Collectors.groupingBy(FrameStructure::getParentId));
        List<FrameStructure> childrenList = map.get(frameStructure.getStructureId());
        if (!frameStructure.isRoot()) {
            // 是否允许下坠
            boolean isAllow = authorityUtil.isAdmin() ? true : scopes.contains(frameStructure.getStructureId());
            if (isAllow) {
                frameStructure.setTerm(termDomainService.queryTermByTermIdAndType(frameStructure.getTermId(), frameStructure.getType()));
                // 只有父节点允许，才会去取子节点
                if (null != childrenList && childrenList.size() > 0) {
                    for (FrameStructure child : childrenList) {
                        FrameStructureVo childVo = new FrameStructureVo();
                        if (null != scopes && !scopes.isEmpty()) {
                            childVo = generateFrameStructureTreeByScopeNew(child, scopes, children);
                        }
                        if (childVo != null) {
                            frameStructure.getChildren().add(childVo);
                        }
                    }
                }
            } else {
                return null;
            }
        } else {
            // 根节点不需要判断
            if ((null != childrenList && childrenList.size() > 0)) {
                for (FrameStructure child : childrenList) {
                    FrameStructureVo childVo = new FrameStructureVo();
                    if (null != scopes && !scopes.isEmpty()) {
                        childVo = generateFrameStructureTreeByScopeNew(child, scopes, children);
                    }
                    if (childVo != null) {
                        frameStructure.getChildren().add(childVo);
                    }
                }
            }
        }
        return dozerUtil.mapGeneric(frameStructure, FrameStructureVo.class);
    }

    /**
     * 根据权限获取可读取的路由
     *
     * @param frameStructure
     * @param scopes
     * @return
     */
    private List<String> getFrameStructureRoutersByScope(FrameStructure frameStructure, List<Long> scopes, List<FrameStructure> children) {
        List<String> routers = new ArrayList<>();
        Map<Long, List<FrameStructure>> map = children.stream().filter(x -> x.getParentId() != null).collect(Collectors.groupingBy(FrameStructure::getParentId));
        List<FrameStructure> childrenList = map.get(frameStructure.getStructureId());
        if (!frameStructure.isRoot()) {
            // 是否允许下坠
            boolean isAllow = scopes.contains(frameStructure.getStructureId());

            if (isAllow) {
                Object attribute = termDomainService.getAttribute(frameStructure.getType(), frameStructure.getTermId(), routerPath);
                if (attribute != null) {
                    routers.add(String.valueOf(attribute));
                }

                // 只有父节点允许，才会去取子节点
                if ((null != childrenList && childrenList.size() > 0)) {
                    for (FrameStructure child : childrenList) {
                        List<String> childRouters = getFrameStructureRoutersByScope(child, scopes, children);
                        if (childRouters.size() > 0) {
                            routers.addAll(childRouters);
                        }
                    }
                }
            } else {
                return routers;
            }
        } else {

            if ((null != childrenList && childrenList.size() > 0)) {
                for (FrameStructure child : childrenList) {
                    List<String> childRouters = getFrameStructureRoutersByScope(child, scopes, children);
                    if (childRouters.size() > 0) {
                        routers.addAll(childRouters);
                    }
                }
            }
        }

        return routers;
    }

    @Override
    public List<Long> getStructureIdsByScope(String rootCode, List<FrameStructure> children) {
        List<Long> structureIds = new ArrayList<>();
        List<Long> roleIds = new ArrayList<>();

        List<RoleMember> roleMembers = roleMemberRepository.selectRoleMemberByPersonId(authorityUtil.getPersonId());
        if (null != roleMembers && !roleMembers.isEmpty()) {
            roleMembers.stream().forEach(roleMember ->
                    roleIds.add(roleMember.getRoleId()));
        }
        structureIds.addAll(rolePermissionDetailDomainService.getScopeStructureIdsByRootCodeAndRoleIds(rootCode, roleIds, children));

        // 可以获取到的结构id
        return structureIds.stream().distinct().collect(Collectors.toList());
    }

    @Override
    public FrameStructureVo getMenuInfrastructureByScope(String rootCode, List<Long> scopes) {
        // 获取根节点
        FrameStructure frameStructure = frameStructureDomainService.queryFrameStructureByRootCode(rootCode);

        return generateFrameStructureTreeByScope(frameStructure, scopes);
    }

    @Override
    public FrameStructureVo getMenuInfrastructureByScopeNew(String rootCode, List<Long> scopes, List<FrameStructure> children) {
        // 获取根节点
        FrameStructure frameStructure = frameStructureDomainService.queryFrameStructureByRootCode(rootCode);

        return generateFrameStructureTreeByScopeNew(frameStructure, scopes, children);
    }

    @Override
    public List<String> queryMenuInfrastructureRoutersByScope(String rootCode, List<Long> scopes, List<FrameStructure> children) {
        FrameStructure frameStructure = frameStructureDomainService.queryFrameStructureByRootCode(rootCode);

        return getFrameStructureRoutersByScope(frameStructure, scopes, children);
    }

    @Override
    public AuthorityAccess pcLoginFast(String account, String password) {
        // 验证账号可用性
        AccountBasic accountBasic = accountBasicRepository.selectByMobileOrUserName(account);
        // 账号是否存在
        if (accountBasic == null) {
            throw LogicException.raise(CustomError.ACCOUNT_NOT_EXIST);
        }
        // 判断当前用户是否生效
        if (!accountBasic.isEnable()) {
            throw LogicException.raise(CustomError.USER_DISABLED);
        }
        // 账号密码是否正确
        String md5Str = SecureUtil.md5(password);
        if (!accountBasic.getPassword().equals(md5Str)) {
            throw LogicException.raise(CustomError.PASSWORD_ERROR);
        }
        // 人员是否存在
        List<Long> personIds = new ArrayList<>();
        personIds.add(accountBasic.getPersonId());
        List<PersonSimpleResponse> personInfos = personnelRemoteApiService.getQueryPersons(personIds);
        if (personInfos.isEmpty()) {
            throw LogicException.raise(CustomError.PERSON_NOT_EXIST);
        }
        PersonSimpleResponse personInfo = personInfos.get(0);

        boolean admin = false;
        boolean virtual = false;
        boolean internal = personInfo.isInternal();

        // 生产token
        int var1 = rand.nextInt(20) + 1;
        int var2 = rand.nextInt(20) + 1;
        Snowflake snowflake = IdUtil.createSnowflake(var1, var2);
        String token = String.valueOf(snowflake.nextId());

        // 获取当前登录人的角色
        List<RoleMember> roleMembers = roleMemberRepository.selectRoleMemberByPersonId(accountBasic.getPersonId());
        List<RoleBasic> roleBasics = new ArrayList<>();
        if (!roleMembers.isEmpty()) {
            List<Long> roleIds = roleMembers.stream().map(RoleMember::getRoleId).sorted().collect(Collectors.toList());
            roleBasics = roleBasicRepository.selectByRoleIds(roleIds);

            // 判断是否为管理员
            for (RoleBasic roleBasic : roleBasics) {
                if (roleBasic.isAdmin()) {
                    admin = true;
                    break;
                }
            }
        }

        if (accountBasic.getPersonId() < 0) {
            virtual = true;
        }
        if (!admin && (virtual || accountBasic.isAdmin())) {
            admin = true;
        }

        AuthorityInfo initScopeTopPermissionInfo = getInitScopeTopPermissionInfo(admin, internal, personInfo.getPersonId());

        AuthorityAccess authorityAccess = dozerUtil.convertor(accountBasic, AuthorityAccess.class);
        authorityAccess.setAdmin(admin);
        authorityAccess.setVirtual(virtual);
        authorityAccess.setInternal(internal);
        authorityAccess.setLastName(personInfo.getLastName());
        authorityAccess.setToken(token);
        authorityAccess.setEmployeeNum(personInfo.getEmployeeNum());
        authorityAccess.setGenderMeaning(personInfo.getGenderMeaning());
        authorityAccess.setImageUUID(personInfo.getImageUUID());
        authorityAccess.setLoginDateTime(LocalDateTime.now());
        authorityAccess.setRoles(roleBasics);
        authorityAccess.setInternalAssignments(initScopeTopPermissionInfo.getInternalAssignments());
        authorityAccess.setProjectAssignments(initScopeTopPermissionInfo.getProjectAssignments());
        authorityAccess.setDataScope(initScopeTopPermissionInfo.getDataScope());
        authorityAccess.setFirstLogin(accountBasic.isFirst());
        authorityAccess.setPersonLevel(initScopeTopPermissionInfo.getPersonLevel());

        // 判断服务器上是否已经有登陆信息
        // userTokenRepository.saveTokenAccessAndExpress(ConstantField.accessSessionPcPath, authorityAccess, ConstantField.clientPcLive);

        String authorityAccessJson = jsonHelper.objectToJson(authorityAccess);
        redisUtil.set(ISMEDI_ACCESS_TOKEN + ":" + token, authorityAccessJson, TOKEN_TIME);

        // 请求上绑定token
        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        request.getSession().setAttribute(ISMEDI_ACCESS_TOKEN, authorityAccess.getToken());

        authorityAccess.setNodeInfo(initScopeTopPermissionInfo.getNodeInfo());

        return authorityAccess;
    }

    @Override
    public AuthorityAccess mobileLoginFast(String account, String password, String clientId) {
        // 验证账号可用性
        AccountBasic accountBasic = accountBasicRepository.selectByMobileOrUserName(account);
        // 账号是否存在
        if (accountBasic == null) {
            throw LogicException.raise(CustomError.ACCOUNT_NOT_EXIST);
        }
        // 判断当前用户是否生效
        if (!accountBasic.isEnable()) {
            throw LogicException.raise(CustomError.USER_DISABLED);
        }
        // 账号密码是否正确
        String md5Str = SecureUtil.md5(password);
        if (!accountBasic.getPassword().equals(md5Str)) {
            throw LogicException.raise(CustomError.PASSWORD_ERROR);
        }
        // 人员是否存在
        List<Long> personIds = new ArrayList<>();
        personIds.add(accountBasic.getPersonId());
        List<PersonSimpleResponse> personInfos = personnelRemoteApiService.getQueryPersons(personIds);
        if (personInfos.isEmpty()) {
            throw LogicException.raise(CustomError.PERSON_NOT_EXIST);
        }
        if (null != clientId) {
            accountBasic.setClientId(clientId);
        }
        accountBasic = accountBasicRepository.doUpdate(accountBasic);
        PersonSimpleResponse personInfo = personInfos.get(0);

        boolean admin = false;
        boolean virtual = false;
        boolean internal = personInfo.isInternal();

        // 生产token
        int var1 = rand.nextInt(20) + 1;
        int var2 = rand.nextInt(20) + 1;
        Snowflake snowflake = IdUtil.createSnowflake(var1, var2);
        String token = String.valueOf(snowflake.nextId());

        // 获取当前登录人的角色
        List<RoleMember> roleMembers = roleMemberRepository.selectRoleMemberByPersonId(accountBasic.getPersonId());
        List<RoleBasic> roleBasics = new ArrayList<>();
        if (!roleMembers.isEmpty()) {
            List<Long> roleIds = roleMembers.stream().map(RoleMember::getRoleId).sorted().collect(Collectors.toList());
            roleBasics = roleBasicRepository.selectByRoleIds(roleIds);

            // 判断是否为管理员
            for (RoleBasic roleBasic : roleBasics) {
                if (roleBasic.isAdmin()) {
                    admin = true;
                    break;
                }
            }
        }
        if (accountBasic.getPersonId() < 0) {
            virtual = true;
        }
        if (!admin && (virtual || accountBasic.isAdmin())) {
            admin = true;
        }

        AuthorityInfo initScopeTopPermissionInfo = getInitScopeTopPermissionInfo(admin, internal, personInfo.getPersonId());

        AuthorityAccess authorityAccess = dozerUtil.convertor(accountBasic, AuthorityAccess.class);
        authorityAccess.setAdmin(admin);
        authorityAccess.setVirtual(virtual);
        authorityAccess.setInternal(internal);
        authorityAccess.setLastName(personInfo.getLastName());
        authorityAccess.setToken(token);
        authorityAccess.setEmployeeNum(personInfo.getEmployeeNum());
        authorityAccess.setGenderMeaning(personInfo.getGenderMeaning());
        authorityAccess.setImageUUID(personInfo.getImageUUID());
        authorityAccess.setLoginDateTime(LocalDateTime.now());
        authorityAccess.setRoles(roleBasics);
        authorityAccess.setInternalAssignments(initScopeTopPermissionInfo.getInternalAssignments());
        authorityAccess.setProjectAssignments(initScopeTopPermissionInfo.getProjectAssignments());
        authorityAccess.setDataScope(initScopeTopPermissionInfo.getDataScope());
        authorityAccess.setFirstLogin(accountBasic.isFirst());
        authorityAccess.setPersonLevel(initScopeTopPermissionInfo.getPersonLevel());

        // 判断服务器上是否已经有登陆信息
        // userTokenRepository.saveTokenAccessAndExpress(ConstantField.accessSessionMobilePath, authorityAccess, ConstantField.clientMobileLive);

        String authorityAccessJson = jsonHelper.objectToJson(authorityAccess);
        redisUtil.set(ISMEDI_ACCESS_TOKEN + ":" + token, authorityAccessJson, TOKEN_TIME);

        // 请求上绑定token
        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        request.getSession().setAttribute(ISMEDI_ACCESS_TOKEN, authorityAccess.getToken());

        authorityAccess.setNodeInfo(initScopeTopPermissionInfo.getNodeInfo());

        return authorityAccess;
    }

    @Override
    public AuthorityInfo getInitScopeTopPermissionInfo(String device) {
        Long personId = authorityUtil.getPersonId();
        boolean admin = authorityUtil.isAdmin();
        boolean internal = authorityUtil.isInternal();

        AuthorityInfo initScopeTopPermissionInfo = getInitScopeTopPermissionInfo(admin, internal, personId);

        if (null != device) {
            switch (device) {
                case "pc":
                    userTokenRepository.refreshDataScope(ConstantField.accessSessionPcPath, ConstantField.clientPcLive, initScopeTopPermissionInfo, device);
                    break;
                case "mobile":
                    userTokenRepository.refreshDataScope(ConstantField.accessSessionMobilePath, ConstantField.clientMobileLive, initScopeTopPermissionInfo, device);
                    break;
                default:
                    throw LogicException.raise(CustomError.DEVICE_NOT_FOUND);
            }
        }
        return initScopeTopPermissionInfo;
    }

    private AuthorityInfo getInitScopeTopPermissionInfo(boolean admin, boolean internal, Long personId) {
        AuthorityInfo authorityInfo = new AuthorityInfo();
        Map<String, List<Long>> dataScope = new HashMap<>();
        // 加载初始化的三级组织
        List<ProjectBasicInfoResponse> accessProjects = new ArrayList<>();
        List<HrOrganizationInfoResponse> accessOrganizations = new ArrayList<>();
        NodeInfo node1 = new NodeInfo();
        List<NodeInfo> node2s = new ArrayList<>();

        // 初始化组织权限和项目权限
        List<Long> organizationScope = new ArrayList<>();
        List<Long> projectScope = new ArrayList<>();

        List<HrOrganizationInfoResponse> allOrganizations = dozerUtil.convertor(organizationRemoteApiService.getAllHrOrganization(), HrOrganizationInfoResponse.class);
        List<ProjectBasicInfoResponse> allProjects = dozerUtil.convertor(constructionProjectRemoteApiService.getQueryAllProjectBasicList(), ProjectBasicInfoResponse.class);
        HrOrganizationInfoResponse hrOrganizationResponseRoot = allOrganizations.stream().filter(HrOrganizationInfoResponse::isRoot).findFirst().orElseThrow(() -> LogicException.raise(CustomError.PROJECT_NOT_ROOT));
        Map<Long, List<HrOrganizationInfoResponse>> organizationIdMap = allOrganizations.stream().collect(Collectors.groupingBy(HrOrganizationInfoResponse::getHrOrganizationId));

        // 加载分配信息
        List<InternalAssignmentResponse> internAssignments = personnelRemoteApiService.getInternAssignment(personId);
        if (!internAssignments.isEmpty()) {
            for (InternalAssignmentResponse internAssignment : internAssignments) {
                HrOrganizationInfoResponse hrOrganizationInfoResponse = organizationIdMap.get(internAssignment.getHrOrganizationId()).get(0);
                internAssignment.setHrOrganizationCode(hrOrganizationInfoResponse.getOrganizationCode());
                internAssignment.setHrOrganizationName(hrOrganizationInfoResponse.getFullName());
                internAssignment.setHrOrganizationShortName(hrOrganizationInfoResponse.getShortName());
                internAssignment.setHrOrganizationType(hrOrganizationInfoResponse.getType());
                internAssignment.setHrOrganizationTypeMeaning(hrOrganizationInfoResponse.getTypeMeaning());
                HrOrganizationInfoResponse subOrganization = hrOrganizationInfoResponse;
                if (hrOrganizationInfoResponse.getType().equals("SUBORDINATE_ORGANIZATION")) {
                    subOrganization = getParentOrganization(hrOrganizationInfoResponse, organizationIdMap);
                }
                internAssignment.setSubHrOrganizationId(subOrganization.getHrOrganizationId());
                internAssignment.setSubHrOrganizationName(subOrganization.getFullName());
            }
        }
        List<ProjectAssignmentResponse> projectAssignment = constructionProjectRemoteApiService.getQueryProjectAssignmentsByPersonIdNoToken(personId);

        node1.setId(hrOrganizationResponseRoot.getHrOrganizationId());
        node1.setNodeId("c" + hrOrganizationResponseRoot.getHrOrganizationId().toString());
        node1.setNodeName(hrOrganizationResponseRoot.getFullName());
        node1.setType("organization");

        // 管理员
        if (admin) {
            accessOrganizations = allOrganizations;
            accessProjects = allProjects;
        }

        boolean haveOrganization = true;

        // 企业人员
        if (!admin && internal) {
            // 是否公司领导
            boolean company = false;
            List<HrOrganizationInfoResponse> accessOrganizationTemp = new ArrayList<>();

            List<Long> organizationIds = remotePersonCoreFeignApi.getOrganizationIdWithPersonId(personId).getData();
            if (organizationIds.isEmpty()) {
                haveOrganization = false;
            }
            if (haveOrganization) {
                List<HrOrganizationInfoResponse> organizationTemp = allOrganizations.stream().filter(organization -> organizationIds.contains(organization.getHrOrganizationId())).collect(Collectors.toList());
                for (HrOrganizationInfoResponse organization : organizationTemp) {
                    if (organization.getType().equals("COMPANY") || organization.getType().equals("COMPANY_LEADER") || organization.getType().equals("COMPANY_MANAGEMENT_ORGANIZATION")) {
                        company = true;
                    }
                    if (organization.getType().equals("PROJECT_MANAGEMENT_ORGANIZATION")) {
                        accessOrganizationTemp.add(organization);
                    }
                    if (organization.getType().equals("SUBORDINATE_ORGANIZATION")) {
                        // 下级部门一直向上找  直到非下级部门
                        HrOrganizationInfoResponse parentOrganization = getParentOrganization(organization, organizationIdMap);
                        accessOrganizationTemp.add(parentOrganization);
                    }
                }

                if (company) {
                    accessOrganizations = allOrganizations;
                    accessProjects = allProjects;
                } else {
                    node1.setEnable(false);
                    // 依据主体院找到所属项目
                    accessOrganizations = accessOrganizationTemp;
                    List<Long> accessOrganizationIds = accessOrganizationTemp.stream().map(HrOrganizationInfoResponse::getHrOrganizationId).collect(Collectors.toList());
                    accessProjects = allProjects.stream().filter(project -> accessOrganizationIds.contains(project.getHrOrganizationId())).collect(Collectors.toList());

                    if (null != projectAssignment && !projectAssignment.isEmpty()) {
                        Map<Long, List<ProjectBasicInfoResponse>> projectIdMap = allProjects.stream().collect(Collectors.groupingBy(ProjectBasicInfoResponse::getProjectId));

                        for (ProjectAssignmentResponse projectAssignmentResponse : projectAssignment) {
                            ProjectBasicInfoResponse projectBasicInfoResponse = projectIdMap.get(projectAssignmentResponse.getProjectId()).get(0);
                            accessProjects.add(projectBasicInfoResponse);
                        }
                    }
                    HashSet<ProjectBasicInfoResponse> hashSet = new HashSet<>(accessProjects);
                    accessProjects.clear();
                    accessProjects.addAll(hashSet);
                }
            }
        }

        // 项目人员
        if (!admin && (!internal || !haveOrganization)) {
            node1.setEnable(false);
            Map<Long, List<ProjectBasicInfoResponse>> projectIdMap = allProjects.stream().collect(Collectors.groupingBy(ProjectBasicInfoResponse::getProjectId));

            for (ProjectAssignmentResponse projectAssignmentResponse : projectAssignment) {
                ProjectBasicInfoResponse projectBasicInfoResponse = projectIdMap.get(projectAssignmentResponse.getProjectId()).get(0);
                accessProjects.add(projectBasicInfoResponse);
            }
        }

        getScopeTopPermissionInfo(accessOrganizations, accessProjects, node1, node2s, organizationIdMap);

        authorityInfo.setNodeInfo(node1);
        authorityInfo.setDataScope(dataScope);
        authorityInfo.setInternalAssignments(dozerUtil.convertor(internAssignments, InternalAssignmentInfo.class));
        authorityInfo.setProjectAssignments(dozerUtil.convertor(projectAssignment, ProjectAssignmentInfo.class));

        // 获取权限范围
        organizationScope = accessOrganizations.stream().sorted(Comparator.comparing(HrOrganizationInfoResponse::getDisplayOrder)).map(HrOrganizationInfoResponse::getHrOrganizationId).collect(Collectors.toList());
        projectScope = accessProjects.stream().map(ProjectBasicInfoResponse::getProjectId).collect(Collectors.toList());

        dataScope.put("project", projectScope);
        dataScope.put("hrOrganization", organizationScope);

        if (organizationScope.size() > 1) {
            authorityInfo.setPersonLevel(INSTITUTION.name());
        }
        if (organizationScope.size() == 1) {
            authorityInfo.setPersonLevel(ORGANIZATION.name());
        }
        if (organizationScope.size() < 1) {
            authorityInfo.setPersonLevel(PROJECT.name());
        }

        return authorityInfo;
    }

    @Override
    public AuthorityInfo getCurrentScopeTopPermissionInfo() {
        AuthorityInfo authorityInfo = new AuthorityInfo();
        // 加载初始化的三级组织
        NodeInfo node1 = new NodeInfo();
        List<NodeInfo> node2s = new ArrayList<>();

        // 初始化组织权限和项目权限
        List<Long> organizationIds = authorityUtil.getDataScope().get("hrOrganization");
        List<Long> projectIds = authorityUtil.getDataScope().get("project");

        List<HrOrganizationInfoResponse> allOrganizations = dozerUtil.convertor(organizationRemoteApiService.getAllHrOrganization(), HrOrganizationInfoResponse.class);
        List<ProjectBasicInfoResponse> allProjects = dozerUtil.convertor(constructionProjectRemoteApiService.getQueryAllProjectBasicList(), ProjectBasicInfoResponse.class);
        HrOrganizationInfoResponse hrOrganizationResponseRoot = allOrganizations.stream().filter(HrOrganizationInfoResponse::isRoot).findFirst().orElseThrow(() -> LogicException.raise(CustomError.PROJECT_NOT_ROOT));
        Map<Long, List<HrOrganizationInfoResponse>> organizationIdMap = allOrganizations.stream().collect(Collectors.groupingBy(HrOrganizationInfoResponse::getHrOrganizationId));

        List<ProjectBasicInfoResponse> accessProjects = allProjects.stream().filter(projectBasicInfoResponse -> projectIds.contains(projectBasicInfoResponse.getProjectId())).collect(Collectors.toList());
        List<HrOrganizationInfoResponse> accessOrganizations = allOrganizations.stream().filter(hrOrganizationInfoResponse -> organizationIds.contains(hrOrganizationInfoResponse.getHrOrganizationId())).collect(Collectors.toList());

        node1.setId(hrOrganizationResponseRoot.getHrOrganizationId());
        node1.setNodeId("c" + hrOrganizationResponseRoot.getHrOrganizationId().toString());
        node1.setNodeName(hrOrganizationResponseRoot.getFullName());
        node1.setType("organization");

        getScopeTopPermissionInfo(accessOrganizations, accessProjects, node1, node2s, organizationIdMap);

        authorityInfo.setNodeInfo(node1);

        return authorityInfo;
    }

    /**
     * 找到下级部门的父节点直到其非下级部门
     *
     * @param currentOrganization 下级部门
     * @param organizationIdMap   组织idMap
     * @return HrOrganizationInfoResponse
     */
    private HrOrganizationInfoResponse getParentOrganization(HrOrganizationInfoResponse currentOrganization, Map<Long, List<HrOrganizationInfoResponse>> organizationIdMap) {
        HrOrganizationInfoResponse organizationInfoResponse = organizationIdMap.get(currentOrganization.getParentId()).get(0);
        if (!organizationInfoResponse.getType().equals("SUBORDINATE_ORGANIZATION")) {
            return organizationInfoResponse;
        } else {
            getParentOrganization(currentOrganization, organizationIdMap);
        }
        return new HrOrganizationInfoResponse();
    }

    /**
     * 根据项目权限范围获取三级组织树
     *
     * @return NodeInfo
     */
    private void getScopeTopPermissionInfo(List<HrOrganizationInfoResponse> accessOrganizations, List<ProjectBasicInfoResponse> accessProjects, NodeInfo node1, List<NodeInfo> node2s, Map<Long, List<HrOrganizationInfoResponse>> organizationIdMap) {
        // 记录node2是否存在
        Map<Long, NodeInfo> node2IdMap = new HashMap<>();

        for (HrOrganizationInfoResponse organization : accessOrganizations) {
            if (!organization.getType().equals("SUBORDINATE_ORGANIZATION") && !organization.getType().equals("COMPANY_MANAGEMENT_ORGANIZATION") && !organization.getType().equals("COMPANY") && !organization.isRoot()) {
                NodeInfo node2 = new NodeInfo();
                node2.setId(organization.getHrOrganizationId());
                node2.setNodeId("o" + organization.getHrOrganizationId());
                node2.setNodeName(organization.getFullName());
                node2.setType("organization");
                node2.setDisplayOrder(organization.getDisplayOrder());
                node2s.add(node2);
                node2IdMap.put(node2.getId(), node2);
            }
        }
        for (ProjectBasicInfoResponse project : accessProjects) {
            NodeInfo node3 = new NodeInfo();
            node3.setId(project.getProjectId());
            node3.setNodeId("p" + project.getProjectId().toString());
            node3.setNodeName(project.getProjectName());
            node3.setType("project");
            HrOrganizationInfoResponse organization = organizationIdMap.get(project.getHrOrganizationId()).get(0);
            if (organization.getType().equals("SUBORDINATE_ORGANIZATION")) {
                organization = getParentOrganization(organization, organizationIdMap);
            }
            if (!node2IdMap.containsKey(organization.getHrOrganizationId())) {
                NodeInfo node2 = new NodeInfo();
                node2.setId(organization.getHrOrganizationId());
                node2.setNodeId("o" + organization.getHrOrganizationId());
                node2.setNodeName(organization.getFullName());
                node2.setType("organization");
                node2.setDisplayOrder(organization.getDisplayOrder());
                node2.setEnable(false);
                node2s.add(node2);
                node2IdMap.put(node2.getId(), node2);
            }
            node2IdMap.get(organization.getHrOrganizationId()).getChildren().add(node3);
        }
        // 排序
        List<NodeInfo> node2sSorted = node2s.stream().sorted(Comparator.comparing(NodeInfo::getDisplayOrder)).collect(Collectors.toList());
        node1.getChildren().addAll(node2sSorted);
    }

    /**
     * 根据项目权限范围获取三级组织树
     *
     * @param projectScope 权限范围
     * @return NodeInfo
     */
    private NodeInfo getScopeTopPermissionInfo(List<HrOrganizationInfoResponse> organizationInfoResponses, List<ProjectBasicInfoResponse> projectScope) {
        ScopeTopPermissionInfoResponse response = new ScopeTopPermissionInfoResponse();
        NodeInfo node1 = new NodeInfo();
        List<NodeInfo> node2s = new ArrayList<>();
        List<Long> instituteIds = new ArrayList<>();

        List<ProjectBasicInfoResponse> allProjectBasicList = dozerUtil.convertor(constructionProjectRemoteApiService.getQueryAllProjectBasicList(), ProjectBasicInfoResponse.class);
        List<HrOrganizationInfoResponse> allHrOrganization = dozerUtil.convertor(organizationRemoteApiService.getAllHrOrganization(), HrOrganizationInfoResponse.class);

        // 获取当前人所属项目id
        Map<String, List<Long>> dataScope = authorityUtil.getDataScope();
        List<Long> projectIdScope = dataScope.getOrDefault("project", null);
        // 如果当前人权限范围没有项目则返回空
        if (null == projectIdScope) {
            return null;
        }

        // 排序
        List<HrOrganizationInfoResponse> allHrOrganizationSorted = allHrOrganization.stream().sorted(Comparator.comparing(HrOrganizationInfoResponse::getDisplayOrder)).collect(Collectors.toList());

        // 获取当前人是否为内部人员
        AuthorityAccessResponse authorityAccessResponse = authorityUtil.getLoginAccess();

        // 每个项目遍历
        allProjectBasicList.forEach(projectBasicResponse -> {
            if (projectIdScope.contains(projectBasicResponse.getProjectId())) {
                NodeInfo node3 = new NodeInfo();
                node3.setId(projectBasicResponse.getProjectId());
                node3.setNodeId("p" + projectBasicResponse.getProjectId().toString());
                node3.setNodeName(projectBasicResponse.getProjectName());
                node3.setType("project");
                // 如果没有组织节点 就新建
                if (!instituteIds.contains(projectBasicResponse.getHrOrganizationId())) {
                    NodeInfo node2 = new NodeInfo();
                    HrOrganizationInfoResponse hrOrganizationResponse = allHrOrganizationSorted.stream().filter(x -> Objects.equals(x.getHrOrganizationId(), projectBasicResponse.getHrOrganizationId())).findFirst().orElseThrow(() -> LogicException.raise(CustomError.PROJECT_NOT_ROOT));
                    node2.setId(hrOrganizationResponse.getHrOrganizationId());
                    node2.setNodeId("o" + hrOrganizationResponse.getHrOrganizationId());
                    node2.setNodeName(hrOrganizationResponse.getFullName());
                    node2.setType("organization");
                    node2.getChildren().add(node3);
                    node2s.add(node2);
                    instituteIds.add(projectBasicResponse.getHrOrganizationId());
                } else {
                    NodeInfo node2 = node2s.stream().filter(x -> Objects.equals(x.getId(), projectBasicResponse.getHrOrganizationId())).findFirst().orElseThrow(() -> LogicException.raise(CustomError.PROJECT_NOT_ROOT));
                    node2.getChildren().add(node3);
                }
            }
        });

        // 获取根节点
        HrOrganizationInfoResponse hrOrganizationResponseRoot = allHrOrganization.stream().filter(HrOrganizationInfoResponse::isRoot).findFirst().orElseThrow(() -> LogicException.raise(CustomError.PROJECT_NOT_ROOT));
        node1.setId(hrOrganizationResponseRoot.getHrOrganizationId());
        node1.setNodeId("c" + hrOrganizationResponseRoot.getHrOrganizationId().toString());
        node1.setNodeName(hrOrganizationResponseRoot.getFullName());
        node1.setType("organization");
        node1.setChildren(node2s);

        return node1;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<FrameStructure> getAllChildren() {
        return frameStructureDomainService.queryAllChildren();
    }
}
